<?php

try {

	$dir = realpath('.');

	echo "Hosts deploy started\n";
	$hostsDeploy = new NS_Deploy_Hosts(array('dir' => $dir));
	$hostsDeploy->deploy();
	echo "Done\n\n";

	echo "Apache VHosts deploy started\n";
	$vhostsDeploy = new NS_Deploy_ApacheVHosts(array('dir' => $dir));
	$vhostsDeploy->deploy();
	echo "Done\n\n";
}
catch(Exception $e) {
	echo "Error occured\n- " . $e->getMessage() . "\n";
}

/**
 * Deploy options class
 * 
 */
abstract class NS_Deploy_Options {

	/**
	 * Options
	 * @var array
	 */
	protected $_options;

	/**
	 * Constructor
	 * @param array
	 */
	public function __construct(array $options = array()){
		$this->_options = array_merge($this->_options, $options);
	}
}

/**
 * Deploy abstract class
 * 
 */
abstract class NS_Deploy_Abstract extends NS_Deploy_Options {

	const STR_DATE = "# Created: %s\r\n\r\n";

	/**
	 * Trim slashes
	 *
	 * @param string $path
	 * @param boolean $trimLeft
	 * @param boolean $trimRight
	 * @return string
	 */
	protected function _trimSlashes($path, $trimLeft = true, $trimRight = true){
		$res = $path;

		if ($trimLeft){
			$first = $path[0];
			if ($first == '/' || $first == '\\')
				$res = substr($res, 1);
		}

		if ($trimRight){
			$last = substr($path, -1);
			if ($last == '/' || $last == '\\')
				$res = substr($res, 0, -1);
		}

		return $res;
	}

	/**
	 * Slice text part
	 *
	 * @param string $text
	 * @param string $start
	 * @param string $end
	 * @return string
	 */
	protected function _cut($text, $start, $end){
		$startPos = strpos($text, $start);
		$endPos = strpos($text, $end);

		if ($startPos > -1 && $endPos > -1)
			$text = substr($text, 0, $startPos) . substr($text, $endPos + strlen($end));

		return $text;
	}
}

/**
 * Hosts deployer
 * 
 */
class NS_Deploy_Hosts extends NS_Deploy_Abstract {

	const STR_PREFIX = "\r\n### Hosts autodeploy start\r\n";
	const STR_POSTFIX = "### Hosts autodeploy end\r\n";
	const STR_HOST = "# Host '%s' (%s)\r\n%s %s\r\n\r\n";
	const STR_DATE = "# Created: %s\r\n\r\n";

	/**
	 * Options
	 * @var array
	 */
	protected $_options = array(
		'hostsFileName' => 'C:/Windows/System32/drivers/etc/hosts',
		'dir' => null,
		'domainReplace' => array('.ru' => '.loc'),
		'patterns' => array('site/www', 'site/public_html', 'site/public')
	);

	/**
	 * Constructor
	 *
	 * @param array
	 */
	public function __construct(array $options){

		parent::__construct($options);

		foreach ($this->_options['patterns'] as $i => $pattern)
			$this->_options['patterns'][$i] = $this->_trimSlashes($pattern);

		if (!isset($this->_options['dir']))
			throw new Exception("Missed option 'dir' in \$options of ".__CLASS__."::__construct");
	}

	/**
	 * Deploy
	 *
	 */
	public function deploy(){

		if (!file_exists($this->_options['hostsFileName']))
			throw new Exception("Hosts file wasn't found ('{$this->_options['hostsFileName']}')");

		if (!is_readable($this->_options['hostsFileName']))
			throw new Exception("Hosts file isn't readable ('{$this->_options['hostsFileName']}')");

		if (!is_writable($this->_options['hostsFileName']))
			throw new Exception("Hosts file isn't writable ('{$this->_options['hostsFileName']}')");

		$hosts = file_get_contents($this->_options['hostsFileName']);
		$hosts = $this->_cut($hosts, self::STR_PREFIX, self::STR_POSTFIX).
			self::STR_PREFIX.
				sprintf(self::STR_DATE, date('r')).
				$this->_formHosts().
			self::STR_POSTFIX;

		file_put_contents($this->_options['hostsFileName'], $hosts);
	}

	/**
	 * Form hosts
	 *
	 * @return string
	 */
	private function _formHosts() {

		$res = array();
		$scandir = $this->_trimSlashes($this->_options['dir'], false);
		foreach (scandir($scandir) as $dir) {
			if ($dir[0] != '.' && is_dir($scandir . '/' . $dir)){
				$host = str_replace(array_keys($this->_options['domainReplace']), array_values($this->_options['domainReplace']), $dir);
				$dirPath = $scandir . '/' . $dir;
				foreach ($this->_options['patterns'] as $pattern){
					$pdir = realpath($dirPath . '/' . $pattern);
					if (file_exists($pdir) && is_dir($pdir))
						$res[] = sprintf(self::STR_HOST, $dir, $pdir, '127.0.0.1', $host);
				}
			}
		}
		return implode('', $res);
	}
}

/**
 * Apache VHosts deployer
 * 
 */
class NS_Deploy_ApacheVHosts extends NS_Deploy_Abstract {

	const STR_PREFIX = "\r\n### Apache VHosts autodeploy start\r\n";
	const STR_POSTFIX = "### Apache VHosts autodeploy end\r\n";
	const STR_VHOST = "# Virtual host '%s' (%s)\r\n<VirtualHost %s>\r\n\tDocumentRoot \"%s\"\r\n\tServerName \"%s\"\r\n</VirtualHost>\r\n\r\n";
	const STR_HEADER = "Listen 127.0.0.1:80\r\nNameVirtualHost 127.0.0.1:80\r\n\r\n";

	/**
	 * Options
	 * @var array
	 */
	protected $_options = array(
		'vhostsFileName' => 'C:/Program Files/Apache Software Foundation/Apache2.2/conf/extra/httpd-vhosts.conf',
		'dir' => null,
		'domainReplace' => array('.ru' => '.loc'),
		'patterns' => array('site/www', 'site/public_html', 'site/public'),
		'applyHeader' => false
	);

	/**
	 * Constructor
	 *
	 * @param array
	 */
	public function __construct(array $options){

		parent::__construct($options);

		foreach ($this->_options['patterns'] as $i => $pattern)
			$this->_options['patterns'][$i] = $this->_trimSlashes($pattern);

		if (!isset($this->_options['dir']))
			throw new Exception("Missed option 'dir' in \$options of ".__CLASS__."::__construct");
	}

	/**
	 * Deploy
	 *
	 */
	public function deploy(){

		if (!file_exists($this->_options['vhostsFileName']))
			throw new Exception("VHosts file wasn't found ('{$this->_options['vhostsFileName']}')");

		if (!is_readable($this->_options['vhostsFileName']))
			throw new Exception("VHosts file isn't readable ('{$this->_options['vhostsFileName']}')");

		if (!is_writable($this->_options['vhostsFileName']))
			throw new Exception("VHosts file isn't writable ('{$this->_options['vhostsFileName']}')");

		$vhosts = file_get_contents($this->_options['vhostsFileName']);
		$vhosts = $this->_cut($vhosts, self::STR_PREFIX, self::STR_POSTFIX).
			self::STR_PREFIX.
				sprintf(self::STR_DATE, date('r')).
				($this->_options['applyHeader'] ? self::STR_HEADER : '').
				$this->_formVHosts().
			self::STR_POSTFIX;

		file_put_contents($this->_options['vhostsFileName'], $vhosts);
	}

	/**
	 * Form vhosts
	 *
	 * @return string
	 */
	private function _formVHosts() {
		$res = array();

		$scandir = $this->_trimSlashes($this->_options['dir'], false);
		foreach (scandir($scandir) as $dir) {
			if ($dir[0] != '.' && is_dir($scandir . '/' . $dir)){
				$host = str_replace(array_keys($this->_options['domainReplace']), array_values($this->_options['domainReplace']), $dir);
				$dirPath = $scandir . '/' . $dir;
				foreach ($this->_options['patterns'] as $pattern){
					$pdir = realpath($dirPath . '/' . $pattern);
					if (file_exists($pdir) && is_dir($pdir))
						$res[] = sprintf(self::STR_VHOST, $dir, $pdir, '127.0.0.1:80', $pdir, $host);
				}
			}
		}

		return implode('', $res);
	}
}
